/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "spatial_softbus_session.h"

#include "constants.h"
#include "securec.h"

#include "softbus_session_listener.h"
#include "spatial_awareness_common.h"

namespace OHOS {
namespace Msdp {
namespace {
static SessionAttribute g_sessionAttr = {
    .dataType = TYPE_BYTES,
};
}
static int32_t SessionOpened(int32_t sessionId, int32_t result);
static void SessionClosed(int32_t sessionId);
static void BytesReceived(int32_t sessionId, const void *data, uint32_t dataLen);
static void MessageReceived(int32_t sessionId, const void *data, uint32_t dataLen);
static void StreamReceived(int32_t sessionId, const StreamData *data, const StreamData *ext,
    const StreamFrameInfo *param);

ISessionListener iSessionListener = {
    .OnSessionOpened = SessionOpened,
    .OnSessionClosed = SessionClosed,
    .OnBytesReceived = BytesReceived,
    .OnMessageReceived = MessageReceived,
    .OnStreamReceived = StreamReceived
};

int32_t SessionOpened(int32_t sessionId, int32_t result)
{
    SPATIAL_LOGI(MODULE_SERVICE, "SessionOpened sessionId: %{public}d, result: %{public}d",
        sessionId, result);
    return SoftbusSessionListener::OnSessionOpened(sessionId, result);
}

void SessionClosed(int32_t sessionId)
{
    SPATIAL_LOGI(MODULE_SERVICE, "SessionClosed sessionId: %{public}d", sessionId);
    SoftbusSessionListener::OnSessionClosed(sessionId);
}

void BytesReceived(int32_t sessionId, const void *data, uint32_t dataLen)
{
    SPATIAL_LOGI(MODULE_SERVICE, "%{public}s enter", __func__);
    SoftbusSessionListener::OnBytesReceived(sessionId, data, dataLen);
}

void MessageReceived(int32_t sessionId, const void *data, uint32_t dataLen)
{
    (void)sessionId;
    (void)data;
    (void)dataLen;
    SPATIAL_LOGI(MODULE_SERVICE, "sessionId:%{public}d, dataLen:%{public}d", sessionId, dataLen);
    SoftbusSessionListener::OnMessageReceived(sessionId, data, dataLen);
}

void StreamReceived(int32_t sessionId, const StreamData *data, const StreamData *ext,
    const StreamFrameInfo *param)
{
    (void)sessionId;
    (void)data;
    (void)ext;
    (void)param;
    SPATIAL_LOGI(MODULE_SERVICE, "sessionId:%{public}d", sessionId);
}

IMPLEMENT_SINGLE_INSTANCE(SpatialSoftbusSession);
SpatialSoftbusSession::~SpatialSoftbusSession()
{
}

int32_t SpatialSoftbusSession::Start()
{
    SPATIAL_LOGI(MODULE_SERVICE, "SoftbusSession start");
    if (sessionServerExist_) {
        SPATIAL_LOGE(MODULE_SERVICE, "session server already exists");
        return SPATIALMANAGER_OK;
    }
    int32_t ret = CreateSessionServer(PKGNAME.c_str(), SESSION_NAME.c_str(), &iSessionListener);
    if (ret != SPATIALMANAGER_OK) {
        SPATIAL_LOGI(MODULE_SERVICE, "CreateSessionServer failed");
        return ret;
    }
    sessionServerExist_ = true;
    return SPATIALMANAGER_OK;
}

int32_t SpatialSoftbusSession::Stop()
{
    if (sessionServerExist_) {
        int32_t ret = RemoveSessionServer(PKGNAME.c_str(), SESSION_NAME.c_str());
        if (ret != SPATIALMANAGER_OK) {
            SPATIAL_LOGI(MODULE_SERVICE, "RemoveSessionServer failed");
            return ret;
        }
    }
    sessionServerExist_ = false;
    return SPATIALMANAGER_OK;
}

int32_t SpatialSoftbusSession::OpenSoftbusSession(const std::string &peerDeviceId)
{
    SPATIAL_LOGI(MODULE_SERVICE, "%{public}s OpenSoftbusSession, peerDeviceId: %{public}s",
        __func__, peerDeviceId.c_str());
    if (sessionOpened_) {
        SPATIAL_LOGE(MODULE_SERVICE, "success to open session");
        return SPATIALMANAGER_OK;
    }

    int32_t sessionId = OpenSession(SESSION_NAME.c_str(),
        SESSION_NAME.c_str(), peerDeviceId.c_str(), std::string("").c_str(), &g_sessionAttr);
    if (sessionId == INVALID_SESSION_ID) {
        return INVALID_SESSION_ID;
    }
    sessionOpened_ = true;
    sessionIdSet_.insert(sessionId);
    return sessionId;
}

void SpatialSoftbusSession::CloseSession(int32_t sessionId)
{
    SPATIAL_LOGI(MODULE_SERVICE, "CloseSession in");
    if (sessionOpened_) {
        ::CloseSession(sessionId);
    }
    sessionOpened_ = false;
}

int32_t SpatialSoftbusSession::SendBytes(int32_t sessionId, const void *data, int32_t len)
{
    SPATIAL_LOGI(MODULE_SERVICE, "in, datalen:%{public}d", len);
    int32_t ret = ::SendBytes(sessionId, data, len);
    if (ret != SPATIALMANAGER_OK) {
        SPATIAL_LOGE(MODULE_SERVICE, "SendMsg ret:%{public}d", ret);
    }
    return SPATIALMANAGER_OK;
}

int32_t SpatialSoftbusSession::SendMsg(int sessionId, const void *data, unsigned int len)
{
    SPATIAL_LOGI(MODULE_SERVICE, "in, datalen:%{public}d", len);
    int32_t ret = ::SendMessage(sessionId, data, len);
    if (ret != SPATIALMANAGER_OK) {
        SPATIAL_LOGE(MODULE_SERVICE, "SendMsg ret:%{public}d", ret);
        return SPATIALMANAGER_FAILED;
    }
    return SPATIALMANAGER_OK;
}

int SpatialSoftbusSession::GetPeerDeviceId(int32_t sessionId, std::string &peerDevId)
{
    char peerDeviceId[DEVICE_UUID_LENGTH] = {0};
    int32_t ret = ::GetPeerDeviceId(sessionId, &peerDeviceId[0], DEVICE_UUID_LENGTH);
    if (ret == 0) {
        peerDevId = peerDeviceId;
        SPATIAL_LOGI(MODULE_SERVICE,
            "GetPeerDeviceId success for session:%{public}d, peerDeviceId:%s", sessionId, peerDevId.c_str());
        return ret;
    }

    SPATIAL_LOGI(MODULE_SERVICE, "GetPeerDeviceId failed for session:%{public}d", sessionId);
    peerDevId = "";
    return SPATIALMANAGER_FAILED;
}

bool SpatialSoftbusSession::IsServer(int sessionId)
{
    return (GetSessionSide(sessionId) == AUTH_SESSION_SIDE_SERVER) ? true : false;
}
} // namespace Msdp
} // namespace OHOS